#include <iostream>

#include "./3rd/cpp-httplib/httplib.h"
#include "api/chart.hpp"
#include "api/distribution.hpp"
#include "api/donee.hpp"
#include "api/donor.hpp"
#include "api/receipt.hpp"
#include "api/user.hpp"
#include "api/warehouse.hpp"
#include "utils/dbutils.hpp"
#include "utils/kvutils.hpp"

using namespace httplib;
using namespace std;

Server svr;

vector<string> apis = {"/register",           "/login",
                       "/changePassword",     "/receipt",
                       "/receipt/total",      "/receipt/add",
                       "/receipt/delete",     "/receipt/edit",
                       "/receipt/search",     "/receipt/donor",
                       "/distribution",       "/distribution/total",
                       "/distribution/add",   "/distribution/delete",
                       "/distribution/edit",  "/distribution/search",
                       "/distribution/donee", "/donor",
                       "/donor/total",        "/donor/add",
                       "/donor/delete",       "/donor/edit",
                       "/donor/search",       "/donee",
                       "/donee/total",        "/donee/add",
                       "/donee/delete",       "/donee/edit",
                       "/donee/search",       "/chart/receipt",
                       "/chart/distribution", "/warehouse",
                       "/warehouse/number"};

void InitCORS() {
  for (const auto &api : apis) {
    svr.Options(api.c_str(), [&](const Request &req, Response &res) {
      res.set_header("Access-Control-Allow-Origin", "*");
      res.set_header("Access-Control-Allow-Headers", "*");
      res.set_header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
    });
  }
}

void InitAPI() {
  svr.Post("/register", Register);
  svr.Post("/login", Login);
  svr.Post("/changePassword", ChangePassword);

  svr.Get("/receipt", Receipt);
  svr.Get("/receipt/total", ReceiptTotal);
  svr.Post("/receipt/add", ReceiptAdd);
  svr.Delete("/receipt/delete", ReceiptDelete);
  svr.Put("/receipt/edit", ReceiptEdit);
  svr.Get("/receipt/search", ReceiptSearch);
  svr.Get("/receipt/donor", ReceiptDonor);

  svr.Get("/distribution", Distribution);
  svr.Get("/distribution/total", DistributionTotal);
  svr.Post("/distribution/add", DistributionAdd);
  svr.Delete("/distribution/delete", DistributionDelete);
  svr.Put("/distribution/edit", DistributionEdit);
  svr.Get("/distribution/search", DistributionSearch);
  svr.Get("/distribution/donee", DistributionDonee);

  svr.Get("/donor", Donor);
  svr.Get("/donor/total", DonorTotal);
  svr.Post("/donor/add", DonorAdd);
  svr.Delete("/donor/delete", DonorDelete);
  svr.Put("/donor/edit", DonorEdit);
  svr.Get("/donor/search", DonorSearch);

  svr.Get("/donee", Donee);
  svr.Get("/donee/total", DoneeTotal);
  svr.Post("/donee/add", DoneeAdd);
  svr.Delete("/donee/delete", DoneeDelete);
  svr.Put("/donee/edit", DoneeEdit);
  svr.Get("/donee/search", DoneeSearch);

  svr.Post("/chart/receipt", ChartReceipt);
  svr.Post("/chart/distribution", ChartDistribution);

  svr.Get("/warehouse", Warehouse);
  svr.Get("/warehouse/number", WarehouseNumber);
}

void Init() {
  InitCORS();
  InitAPI();
  KVWrapper::GetInstance("user")->Init();
  KVWrapper::GetInstance("warehouse")->Init();
  DBWrapper::GetInstance()->Init();
}

int main() {
  Init();

  cout << "Running at http://localhost:5000" << endl;

  svr.listen("localhost", 5000);

  return 0;
}